#include "Texture.h"

namespace DreamEngine
{


CTexture::CTexture(const std::string& name):
	m_name(name),
	m_pTexture(NULL)
{

}

CTexture::~CTexture(void)
{

}

void CTexture::SetTexture(IDirect3DTexture9* pTexture)
{
	m_pTexture = pTexture;
}

bool CTexture::Create(D3DFORMAT textureFormat,
					  m_uint16 width, m_uint16 height, D3DPOOL pool/* =D3DPOOL_MANAGED */, 
	DWORD usage/* =0 */, UINT mipLevel/* =0 */)
{
	if (pRenderSystem == NULL)
	{
		return false;
	}

	SAFE_RELEASE(m_pTexture);

	if (FAILED(pRenderSystem->GetD3DDevice()->CreateTexture(width, height, mipLevel,\
		usage, textureFormat, pool, &m_pTexture, NULL)))
	{
		return false;
	}
	return true;
}

bool CTexture::CreateFromFile(CRenderSystem* pRenderSystem, const std::string& fileName,
	D3DFORMAT textureFormat/* =D3DFMT_A8R8G8B8 */, UINT width/*=0*/, UINT height/*=0*/,
	D3DPOOL pool/* =D3DPOOL_MANAGED */, DWORD usage/* =0 */, int mipLevel/* =0 */)
{
	if (pRenderSystem == NULL)
	{
		return false;
	}
	
	SAFE_RELEASE(m_pTexture);

	m_fileName  = fileName;

	if (mipLevel < 0)
	{
		width = height = D3DX_DEFAULT_NONPOW2;
	}

	HRESULT hr = (D3DXCreateTextureFromFileEx(pRenderSystem->GetD3DDevice(), fileName.c_str(),\
		width, height, mipLevel, usage, textureFormat,\
		pool, D3DX_DEFAULT, D3DX_DEFAULT, 0xFF000000,\
		NULL, NULL, &m_pTexture));

	if (FAILED(hr))
	{
		CFunctions::OutPutDxErrorToDebugWnd(hr);
		return false;
	}
	 
	return true;
}

DWORD CTexture::GetPixelColor(int x, int y)
{
	int pixelByte = CaculatePixelByte(this);
	D3DSURFACE_DESC d3dsddes;
	GetLevelDesc(d3dsddes);
	D3DLOCKED_RECT lockedRectDes;
	m_pTexture->LockRect(0, &lockedRectDes, 0, 0);
	byte* pDestData = static_cast<byte*>(lockedRectDes.pBits);

	DWORD color = 0;
	if (pDestData != NULL)
	{
		for (int iRepeat=0; iRepeat<pixelByte; ++iRepeat)
		{
			color <<= 8;
			color |= pDestData[(y*lockedRectDes.Pitch)+(x*pixelByte)+iRepeat];
		}
	}
	m_pTexture->UnlockRect(0);

	return color;
}

void CTexture::GetPixelColor(OUT D3DCOLORVALUE& color, int x, int y)
{
	DWORD dColor = GetPixelColor(x, y);
	DWORD mask = 0x000000ff;
	color.b = static_cast<byte>(mask&dColor)/255.0f;
	dColor >>= 8;
	color.g =static_cast<byte>(mask&dColor)/255.0f;
	dColor >>= 8;
	color.r = static_cast<byte>(mask&dColor)/255.0f;
	dColor >>= 8;
	color.a = static_cast<byte>(mask&dColor)/255.0f;
}

void CTexture::SetPixelColor(int x, int y, DWORD color)
{
	int pixelByte = CaculatePixelByte(this);
	D3DSURFACE_DESC d3dsddes;
	GetLevelDesc(d3dsddes);
	D3DLOCKED_RECT lockedRectDes;
	m_pTexture->LockRect(0, &lockedRectDes, 0, 0);
	byte* pDestData = static_cast<byte*>(lockedRectDes.pBits);

	if (pDestData != NULL)
	{
		for (int iRepeat=0; iRepeat<pixelByte; ++iRepeat)
		{
			byte vaule = static_cast<byte>((color & 0xff000000)>>24);
			pDestData[(y*lockedRectDes.Pitch)+(x*pixelByte)+iRepeat] = vaule;
			color <<= 8;
		}
	}
	m_pTexture->UnlockRect(0);
}

void CTexture::SetPixelColor(int x, int y, const D3DCOLORVALUE& color)
{
	DWORD dColor = 0;
	dColor |= static_cast<byte>(color.a*255);
	dColor <<= 8;
	dColor |= static_cast<byte>(color.r*255);
	dColor <<= 8;
	dColor |= static_cast<byte>(color.g*255);
	dColor <<= 8;
	dColor |= static_cast<byte>(color.b*255);

	SetPixelColor(x, y, dColor);
}

void CTexture::CopyFrom(CRenderSystem* pRenderSystem, CTexture* pSourceTexture)
{
	if (pSourceTexture!=NULL && this!=pSourceTexture)
	{
		D3DSURFACE_DESC d3dsdsrc;
		pSourceTexture->GetLevelDesc(d3dsdsrc);
		D3DLOCKED_RECT lockedRectSrc;
		pSourceTexture->GetD3DTexture()->LockRect(0, &lockedRectSrc, 0, 0);
		byte* pSrcData = static_cast<byte*>(lockedRectSrc.pBits);
		int pixelByte = CaculatePixelByte(pSourceTexture);

		Create(pRenderSystem, d3dsdsrc.Format,d3dsdsrc.Height, d3dsdsrc.Width, d3dsdsrc.Pool, d3dsdsrc.Usage);
		
		D3DSURFACE_DESC d3dsddes;
		GetLevelDesc(d3dsddes);
		D3DLOCKED_RECT lockedRectDes;
		m_pTexture->LockRect(0, &lockedRectDes, 0, 0);
		byte* pDestData = static_cast<byte*>(lockedRectDes.pBits);

		if (pSrcData!=NULL && pDestData!=NULL)
		{
			int sizex = d3dsdsrc.Width<d3dsddes.Width?d3dsdsrc.Width:d3dsddes.Width;
			int sizey = d3dsdsrc.Height<d3dsddes.Height?d3dsdsrc.Height:d3dsddes.Height;

			for(int y=0; y<sizey; y++ )
			{
				for(int x=0; x<sizex; x++ )
				{
					for (int iRepeat=0; iRepeat<pixelByte; ++iRepeat)
					{
						pDestData[(y*lockedRectDes.Pitch)+(x*pixelByte)+iRepeat] = \
							pSrcData[(y*lockedRectSrc.Pitch)+(x*pixelByte)+iRepeat];
					}
				}
			}
			m_pTexture->UnlockRect(0);
			pSourceTexture->GetD3DTexture()->UnlockRect(0);
		}
	}
}

void CTexture::SaveToFile(const std::string& fileName, \
	D3DXIMAGE_FILEFORMAT fileFormat/* =D3DXIFF_DDS */)
{
	if (m_pTexture==NULL)
	{
		return;
	}

	IDirect3DSurface9* pSursace = NULL;
	m_pTexture->GetSurfaceLevel(0, &pSursace);
	D3DXSaveSurfaceToFile(fileName.c_str(), fileFormat, pSursace, NULL, NULL);
	pSursace->Release();
}



void CTexture::Release()
{
	if (m_pTexture != NULL)
	{
		m_pTexture->Release();
	}
}


int CTexture::CaculatePixelByte(CTexture* pTexture)
{
	if (pTexture == NULL)
	{
		return 0;
	}
	D3DSURFACE_DESC d3dsd;
	pTexture->GetLevelDesc(d3dsd);
	switch(d3dsd.Format)
	{
	case D3DFMT_A8R8G8B8:
	case D3DFMT_X8R8G8B8:
		return 4;

	case D3DFMT_R8G8B8:
		return 3;

	case D3DFMT_X1R5G5B5:
		return 2;

	case D3DFMT_L8:
		return 1;

	default:
		return 4;
	}
}

void CTexture::GetLevelDesc(D3DSURFACE_DESC& d3dsd, int level/* =0 */)
{
	if (m_pTexture != NULL)
	{
		m_pTexture->GetLevelDesc( level, &d3dsd );
	}
}

float CTexture::GetWidth(int level/* =0 */)
{
	D3DSURFACE_DESC d3dsd;
	GetLevelDesc(d3dsd, level/* =0 */);
	return d3dsd.Width;
}

float CTexture::GetHeight(int level/* =0 */)
{
	D3DSURFACE_DESC d3dsd;
	GetLevelDesc(d3dsd, level/* =0 */);
	return d3dsd.Height;
}

}
